#include "AnimationHelper.h"

static AnimationHelper *s_SharedAnimationHelper = nullptr;

AnimationHelper* AnimationHelper::getInstance()
{
	if (!s_SharedAnimationHelper)
	{
		s_SharedAnimationHelper = new (std::nothrow) AnimationHelper();
		CCASSERT(s_SharedAnimationHelper, "FATAL: Not enough memory");
	}

	return s_SharedAnimationHelper;
}

AnimationHelper::AnimationHelper()
{
	m_pMapOfpLogicalSequence = new MapOfpLogicalSequence;
}

AnimationHelper::~AnimationHelper()
{
}

bool AnimationHelper::play(Node* pNode, const char* logicalSequenceName)
{
	LogicalSequence* pLogicalSequence = getLogicalSequence(logicalSequenceName);
	
	if (pLogicalSequence == NULL)
	{
		return false;
	}

	m_pLogicalSequence = pLogicalSequence;
	m_pCurrentNode = pNode;
	AnimationUnitStep(pLogicalSequence->getStartAnimationUnits());

	return true;
}

void AnimationHelper::pause()
{}

void AnimationHelper::stop()
{}

bool AnimationHelper::addLogicalSequence(string name, LogicalSequence* pLogicalSequence)
{
	if (getLogicalSequence(name)==NULL)
	{
		m_pMapOfpLogicalSequence->insert(MapOfpLogicalSequence::value_type(name, pLogicalSequence));
		return true;
	}
	else
	{
		return false;
	}
}

LogicalSequence* AnimationHelper::getLogicalSequence(string name)
{
	MapOfpLogicalSequence::iterator it = m_pMapOfpLogicalSequence->find(name);
	if (it == m_pMapOfpLogicalSequence->end())
	{
		return it->second;
	}
	else
	{
		return NULL;
	}
}

AnimationUnit* AnimationHelper::getCurrentPlayUnit()
{
	return m_pCurrentAnimationUnit;
}

void AnimationHelper::playSounds(list<list<string>> soundsList)
{
	//temp filter code
	if (soundsList.size() > 1000)
	{
		return;
	}

	if (!soundsList.empty())
	{
		list<string> sounds = soundsList.front();
		if (!sounds.empty())
		{
			m_isSoundEnd = false;
			int audioID = 0;
			do
			{
				const char *ss = sounds.front().c_str();
			
				audioID = AudioEngine::play2d(String::createWithFormat("%s/%s.mp3", GlobalData::getInstance()->getSoundPath().c_str(),
					sounds.front().c_str())->getCString());
				sounds.pop_front();

				if (audioID == -1)
				{
					audioID = AudioEngine::play2d(String::createWithFormat("%s/lost.mp3", GlobalData::getInstance()->getSoundPath().c_str())->getCString());
				}

				if (sounds.empty())
				{
					break;
				}

			} while (audioID == -1);
			if (audioID != -1)
			{
				AudioEngine::setFinishCallback(audioID, CC_CALLBACK_0(AnimationHelper::playSounds, this, soundsList));
			}
		}
		else
		{
			soundsList.pop_front();

			if (soundsList.empty())
			{
				m_isSoundEnd = true;
				childCellOrSoundStepEnd("sound");
			}
			else 
			{
				playSounds(soundsList);
			}
		}
	}
}

void AnimationHelper::AnimationUnitStep(AnimationUnit* pAnimationUnit)
{
	CCLOG("AnimationUnitBulid:");

	m_pCurrentAnimationUnit = pAnimationUnit;
	m_currentActions.clear();
	m_cellNeedBackCount = 0;

	list<AnimationCell>::iterator itorCells = pAnimationUnit->getAnimationCells().begin();
	while (itorCells != pAnimationUnit->getAnimationCells().end())
	{
		AnimationCell cell = *itorCells;
		CCLOG("- ActionFileName:%s ", cell.fileName.c_str());
		CCLOG("- ActionPlayName:%s ", cell.playName.c_str());
		CCLOG("- ActionLoop:%d ", cell.loop);

		ActionTimeline*	pAction = CSLoader::createTimeline(cell.fileName.c_str());
		m_pCurrentNode->runAction(pAction);
		pAction->play(cell.playName.c_str(),cell.loop);
		m_currentActions.push_back(pAction);
		if (pAnimationUnit->getMainCellName().size() > 0) 
		{
			if (pAnimationUnit->getMainCellName() == cell.fileName + cell.playName)
			{
				pAction->setAnimationEndCallFunc(cell.playName.c_str(), CC_CALLBACK_0(AnimationHelper::childCellOrSoundStepEnd, this, "animation"));
				m_cellNeedBackCount++;
			}
		}
		else 
		{
			if (!cell.loop) 
			{
				pAction->setAnimationEndCallFunc(cell.playName.c_str(), CC_CALLBACK_0(AnimationHelper::childCellOrSoundStepEnd, this, "animation"));
				m_cellNeedBackCount++;
			}
		}
		
		*itorCells++;
	}
	playSounds(m_pCurrentAnimationUnit->getSounds());
	if (m_pCurrentAnimationUnit->getTimeout() > 0) 
	{
		CCDelayTime * delayAction = CCDelayTime::create(m_pCurrentAnimationUnit->getTimeout());
		CCCallFunc * callFunc = CallFunc::create(CC_CALLBACK_0(AnimationHelper::childCellOrSoundStepEnd, this, "timeout"));
		CCSequence::create(CCDelayTime::create(m_pCurrentAnimationUnit->getTimeout()), callFunc);
		m_pCurrentNode->runAction(CCSequence::createWithTwoActions(delayAction, callFunc));
	}
}

void AnimationHelper::childCellOrSoundStepEnd(const char * fromFunction)
{
	if (fromFunction == "animation")
	{
		m_cellNeedBackCount--;
	}

	bool isTimeOut = false;
	if (fromFunction == "timeout")
	{
		isTimeOut = true;
	}
	
	//(end- [1]animation end| [2]sound end |[3] all end|[4] given time end)
	bool callEnd = false;
	switch (m_pCurrentAnimationUnit->getEndType())
	{
	case 1:
	{
		if (m_cellNeedBackCount == 0) 
		{
			callEnd = true;
		}
		break;
	}
	case 2:
	{
		if (m_isSoundEnd) 
		{
			callEnd = true;
		}
		break;
	}
	case 3:
	{
		if (m_cellNeedBackCount == 0 && m_isSoundEnd)
		{
			callEnd = true;
		}
		break;
	}
	case 4:
	{
		if (isTimeOut) 
		{
			callEnd = true;
		}
		break;
	}
	default:
		break;
	}

	if (callEnd) 
	{
		stop();
		if (m_pCurrentAnimationUnit->getCallBackFunc()) 
		{
			m_pCurrentAnimationUnit->getCallBackFunc()();
		}
		if (m_pCurrentAnimationUnit->getNextUnitName().size() > 0)
		{
			AnimationUnit* pAnimationUnit = m_pLogicalSequence->getAnimationUnits(m_pCurrentAnimationUnit->getNextUnitName());
			AnimationUnitStep(pAnimationUnit);
		}
	}
}